﻿#include "mvs.h"

int getImageFormat(int typeValue){
    int nValue;
    MvGvspPixelType nType = MvGvspPixelType(typeValue);
    nValue = 0;
    if(nType == PixelType_Gvsp_RGB8_Packed)nValue=1;
    return nValue;
}

MVS::MVS(fsConfig *conf)
{
    m_hDevHandle = MV_NULL;
    m_Device = MV_NULL;
    devType = -1;
    typeInfo = "";
    factoryName = "";
    modelInfo = "";
    serialInfo = "";
    deviceVer = "";
    isSdkInit = false;
    isOpenDevice = false;
    isStartGrabbing = false;
    isFrameCallback = false;
    isEventCallback = false;

    memset(&m_ParasInfo,0,sizeof(m_ParasInfo));

    // qStrToCstr("曝光",m_ParasInfo.LabelExposure,sizeof(m_ParasInfo.LabelExposure));
    // qStrToCstr("色度",m_ParasInfo.LabelContrast,sizeof(m_ParasInfo.LabelContrast));
    // qStrToCstr("亮度",m_ParasInfo.LabelBrightness,sizeof(m_ParasInfo.LabelBrightness));
    // qStrToCstr("饱和",m_ParasInfo.LabelSaturation,sizeof(m_ParasInfo.LabelSaturation));
    // qStrToCstr("伽马",m_ParasInfo.LabelGamma,sizeof(m_ParasInfo.LabelGamma));

    fsConf = conf;
}

MVS::~MVS()
{
    closeCamera();
    sdkFinal();
}

bool MVS::isOpen(void)
{
    return (m_hDevHandle != MV_NULL && m_Device != MV_NULL);
}

bool MVS::isGrabbing(void){
    return isOpen()&&isStartGrabbing;
}

bool MVS::isDev(void){
    return isSdkInit&&m_Device != MV_NULL;
}

//获取SDK版本信息
QString MVS::getSDKVersion(void){
    unsigned int ver = MV_CC_GetSDKVersion();
    QString vers = QString("SDK-V%0.%1.%2.%3").arg(ver>>24).arg((ver>>16)&0xff).arg((ver>>8)&0xff).arg(ver&0xff);
    return vers;
}

//SDK初始化
void MVS::sdkInit(void){
    //初始化
    if(!isSdkInit){
        errRet = MV_CC_Initialize();
        if(errRet != MV_OK){
            //异常
            retInfo(QString("Initialize %0").arg(errRet));
            return;
        }
        isSdkInit = true;
    }
}

//SDK释放
void MVS::sdkFinal(void){
    if(isSdkInit){
        errRet = MV_CC_Finalize();
        if(errRet != MV_OK){
            //异常
            retInfo(QString("Finalize %0").arg(errRet));
            return;
        }
        isSdkInit = false;
    }
}

void MVS::Init(void)
{
    sdkInit();
    // retInfo(QString("SDKVersion %0 %1").arg(getSDKVersion()).arg(isSdkInit));
    //枚举设备
    memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
    errRet = EnumDevices(&m_stDevList);

    if(errRet != MV_OK){
        //异常
        retInfo(QString("EnumDevices %0").arg(errRet));
        return;
    }
    retInfo(QString("DeviceNum %0").arg(m_stDevList.nDeviceNum));
    if(m_stDevList.nDeviceNum == 0){
        //无相机
        retInfo(QString("Find No Devices !"));
        return;
    }
    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++)
    {
        MV_CC_DEVICE_INFO* pDeviceInfo = m_stDevList.pDeviceInfo[i];
        if (MV_NULL == pDeviceInfo){
            continue;
        }
        if(pDeviceInfo->nTLayerType != MV_GIGE_DEVICE){
            continue;
        }
        devType = pDeviceInfo->nTLayerType;
        typeInfo = "GigE";
        retInfo(typeInfo);
        //设备信息：厂商，型号，序列号，设备版本
        factoryName = QString("%0").arg((char *)pDeviceInfo->SpecialInfo.stGigEInfo.chManufacturerName);
        retInfo(factoryName);
        modelInfo = QString("%0").arg((char *)pDeviceInfo->SpecialInfo.stGigEInfo.chModelName);
        retInfo(modelInfo);
        serialInfo = QString("%0").arg((char *)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber);
        deviceVer = QString("%0").arg((char *)pDeviceInfo->SpecialInfo.stGigEInfo.chDeviceVersion);


        retInfo(deviceVer);
        m_Device= pDeviceInfo;
        break;
    }
}

QString MVS::getDeviceName(void)
{
    return QString("%0:%1(%2)").arg(typeInfo).arg(modelInfo).arg(serialInfo);
}

QString MVS::getMvsInfo(void){
    return QString("%0->%1,%2").arg(factoryName).arg(deviceVer).arg(getSDKVersion());
}

PARAMS_VAR MVS::getPara(void){
    return m_ParasInfo;
}

void MVS::setPara(const int nums,const int errs,const int losts){
    m_ParasInfo.ImageNums = nums;
    m_ParasInfo.ErrorNums = errs;
    m_ParasInfo.LostNums = losts;
}

bool MVS::isError(void){
    return (errRet == 0);
}

QString MVS::getError(void){
    if(errRet){
        return QString("0x%0").arg(QString::number(errRet,16).replace("f", ""));
    }
    return QString("Ok");
}

// 获取所有参数
void MVS::getParms(void){
    if(!isDev()){
        return;
    }
    bool bValue = false;
    MVCC_INTVALUE_EX stIntValue = { 0 };
    MVCC_FLOATVALUE stFloatValue = {0};
    MVCC_ENUMVALUE stEnumPixelFormatValue = { 0 };

    m_ParasInfo.DeviceType = devType;
    qStrToCstr(factoryName,m_ParasInfo.FactoryName,sizeof(m_ParasInfo.FactoryName));
    qStrToCstr(modelInfo,m_ParasInfo.DeviceModel,sizeof(m_ParasInfo.DeviceModel));
    qStrToCstr(serialInfo,m_ParasInfo.Serials,sizeof(m_ParasInfo.Serials));
    qStrToCstr(deviceVer,m_ParasInfo.ParamVersion,sizeof(m_ParasInfo.ParamVersion));

//    int             Flip;
//    int             FlipMin;
//    int             FlipMax;
//    int             Mirror;
//    int             MirrorMin;
//    int             MirrorMax;

    getExposureTime(m_ParasInfo.ExposureTime,m_ParasInfo.ExposureTimeMin,m_ParasInfo.ExposureTimeMax);
    retInfo(QString("getExposureTime %0, min %1 max %2").arg(m_ParasInfo.ExposureTime).arg(m_ParasInfo.ExposureTimeMin).arg(m_ParasInfo.ExposureTimeMax));

    // getHue(m_ParasInfo.Contrast,m_ParasInfo.ContrastMin,m_ParasInfo.ContrastMax);
    // retInfo(QString("getHue %0, min %1 max %2").arg(m_ParasInfo.Contrast).arg(m_ParasInfo.ContrastMin).arg(m_ParasInfo.ContrastMax));

    // getBrightness(m_ParasInfo.Brightness,m_ParasInfo.BrightnessMin,m_ParasInfo.BrightnessMax);
    // retInfo(QString("getBrightness %0, min %1 max %2").arg(m_ParasInfo.Brightness).arg(m_ParasInfo.BrightnessMin).arg(m_ParasInfo.BrightnessMax));

    // getSaturation(m_ParasInfo.Saturation,m_ParasInfo.SaturationMin,m_ParasInfo.SaturationMax);
    // retInfo(QString("getSaturation %0, min %1 max %2").arg(m_ParasInfo.Saturation).arg(m_ParasInfo.SaturationMin).arg(m_ParasInfo.SaturationMax));

    // getGamma(m_ParasInfo.Gamma,m_ParasInfo.GammaMin,m_ParasInfo.GammaMax);
    // retInfo(QString("getGamma %0, min %1 max %2").arg(m_ParasInfo.Gamma).arg(m_ParasInfo.GammaMin).arg(m_ParasInfo.GammaMax));

    GetEnumValue("DeviceScanType",&stEnumPixelFormatValue);
    m_ParasInfo.DeviceScanType = stEnumPixelFormatValue.nCurValue;
    retInfo(QString("DeviceScanType %0").arg(m_ParasInfo.DeviceScanType));

    GetIntValue("DeviceUptime",&stIntValue);
    m_ParasInfo.DeviceUptime = stIntValue.nCurValue;
    retInfo(QString("DeviceUptime %0").arg(m_ParasInfo.DeviceUptime));

    //图像
    GetIntValue("WidthMax",&stIntValue);
    m_ParasInfo.WidthMax = stIntValue.nCurValue;

    GetIntValue("HeightMax",&stIntValue);
    m_ParasInfo.HeightMax = stIntValue.nCurValue;

    retInfo(QString("widthMax %0, heightMax %1").arg(m_ParasInfo.WidthMax).arg(m_ParasInfo.HeightMax));

    GetIntValue("Width",&stIntValue);
    m_ParasInfo.Width = stIntValue.nCurValue;

    GetIntValue("Height",&stIntValue);
    m_ParasInfo.Height = stIntValue.nCurValue;

    GetIntValue("OffsetX",&stIntValue);
    m_ParasInfo.OffsetX = stIntValue.nCurValue;

    GetIntValue("OffsetY",&stIntValue);
    m_ParasInfo.OffsetX = stIntValue.nCurValue;

    retInfo(QString("width %0, height %1, offset=(%2,%3)")
                .arg(m_ParasInfo.Width).arg(m_ParasInfo.Height).arg(m_ParasInfo.OffsetX).arg(m_ParasInfo.OffsetY));
    //采集
    GetIntValue("AcquisitionMode",&stIntValue);
    m_ParasInfo.AcquisitionMode = stIntValue.nCurValue;
    retInfo(QString("AcquisitionMode %0").arg(m_ParasInfo.AcquisitionMode));

    m_ParasInfo.AcquisitionBurstFrameCount = 1;
    if(m_ParasInfo.AcquisitionMode){
        GetIntValue("AcquisitionBurstFrameCount",&stIntValue);
        m_ParasInfo.AcquisitionBurstFrameCount = stIntValue.nCurValue;
        retInfo(QString("AcquisitionBurstFrameCount %0").arg(m_ParasInfo.AcquisitionBurstFrameCount));
    }

    GetIntValue("AcquisitionLineRate",&stIntValue);
    m_ParasInfo.AcquisitionLineRate = stIntValue.nCurValue;
    retInfo(QString("AcquisitionLineRate %0").arg(m_ParasInfo.AcquisitionLineRate));

    GetBoolValue("AcquisitionLineRateEnable",&bValue);
    m_ParasInfo.AcquisitionLineRateEnable = bValue;
    retInfo(QString("AcquisitionLineRateEnable %0").arg(m_ParasInfo.AcquisitionLineRateEnable));

    GetIntValue("ResultingLineRate",&stIntValue);
    m_ParasInfo.ResultingLineRate = stIntValue.nCurValue;
    retInfo(QString("ResultingLineRate %0").arg(m_ParasInfo.ResultingLineRate));

    GetFloatValue("ResultingFrameRate",&stFloatValue);
    m_ParasInfo.ResultingFrameRate = stFloatValue.fCurValue;
    retInfo(QString("ResultingFrameRate %0").arg(getNumber(m_ParasInfo.ResultingFrameRate)));

    stEnumPixelFormatValue = {0};
    GetEnumValue("PixelFormat",&stEnumPixelFormatValue);
    m_ParasInfo.ImageFormat = getImageFormat(stEnumPixelFormatValue.nCurValue);
    retInfo(QString("PixelFormat %0").arg(m_ParasInfo.ImageFormat));

    //行触发：触发选择-LineStart，触发模式-On，触发源-FrequencyConverter ，触发-RisingEdge
    errRet = GetEnumValue("TriggerSelector",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.TriggerSelector = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("TriggerSelector %0 %1").arg(m_ParasInfo.TriggerSelector).arg(getError()));

    errRet = GetEnumValue("TriggerMode",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.TriggerMode = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("TriggerMode %0 %1").arg(m_ParasInfo.TriggerMode).arg(getError()));

    errRet = GetEnumValue("TriggerSource",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.TriggerSource = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("TriggerSource %0 %1").arg(m_ParasInfo.TriggerSource).arg(getError()));

    errRet = GetEnumValue("TriggerActivation",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.TriggerActivation = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("TriggerActivation %0 %1").arg(m_ParasInfo.TriggerActivation).arg(getError()));

    //编码控制:编码器选择-Encode0，编码A源选择-Line0，编码B源选择-Line3，编码触发模式-ForwardOnly，编码计数模式-IgnoreDirection，计数器，计数最大值-10000
    errRet = GetEnumValue("EncoderSelector",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.EncoderSelector = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("EncoderSelector %0 %1").arg(m_ParasInfo.EncoderSelector).arg(getError()));

    errRet = GetEnumValue("EncoderSourceA",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.EncoderSourceA = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("EncoderSourceA %0 %1").arg(m_ParasInfo.EncoderSourceA).arg(getError()));

    errRet = GetEnumValue("EncodeSourceB",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.EncoderSourceB = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("EncoderSourceB %0 %1").arg(m_ParasInfo.EncoderSourceB).arg(getError()));

    errRet = GetEnumValue("EncoderTriggerMode",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.EncoderTriggerMode = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("EncoderTriggerMode %0 %1").arg(m_ParasInfo.EncoderTriggerMode).arg(getError()));

    errRet = GetEnumValue("EncoderCounterMode",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.EncoderCounterMode = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("EncoderCounterMode %0 %1").arg(m_ParasInfo.EncoderCounterMode).arg(getError()));

    errRet = GetIntValue("EncoderCounter",&stIntValue);
    m_ParasInfo.EncoderCounter = stIntValue.nCurValue;
    errRet = GetIntValue("EncoderCounterMax",&stIntValue);
    m_ParasInfo.EncoderCounterMax = stIntValue.nCurValue;
    retInfo(QString("EncoderCounter %0 EncoderCounterMax %1").arg(m_ParasInfo.EncoderCounter).arg(m_ParasInfo.EncoderCounterMax));

    //分频控制：分频器输入源-EncodeModuleOut，分频器信号方向-RisingEdge，前置调节-1，倍频调节-1，后置调节-1
    errRet = GetEnumValue("InputSource",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.InputSource = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("InputSource %0 %1").arg(m_ParasInfo.InputSource).arg(getError()));
    errRet = GetEnumValue("SignalAlignment",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.SignalAlignment = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("SignalAlignment %0 %1").arg(m_ParasInfo.SignalAlignment).arg(getError()));
    errRet = GetIntValue("PreDivider",&stIntValue);
    if(isError()){
        m_ParasInfo.PreDivider = stIntValue.nCurValue;
    }
    retInfo(QString("PreDivider %0 %1").arg(m_ParasInfo.PreDivider).arg(getError()));
    errRet = GetIntValue("Multiplier",&stIntValue);
    if(isError()){
        m_ParasInfo.Multiplier = stIntValue.nCurValue;
    }
    retInfo(QString("Multiplier %0 %1").arg(m_ParasInfo.Multiplier).arg(getError()));
    // int             ;
    errRet = GetIntValue("PostDivider",&stIntValue);
    if(isError()){
        m_ParasInfo.PostDivider = stIntValue.nCurValue;
    }
    retInfo(QString("PostDivider %0 %1").arg(m_ParasInfo.PostDivider).arg(getError()));
    //平场矫正：校正选择-PRNUCCorrection，平场使能-Off，
    errRet = GetEnumValue("ShadingSelector",&stEnumPixelFormatValue);
    if(isError()){
        m_ParasInfo.ShadingSelector = stEnumPixelFormatValue.nCurValue;
    }
    retInfo(QString("ShadingSelector %0 %1").arg(m_ParasInfo.ShadingSelector).arg(getError()));

    errRet = GetBoolValue("PRNUCROIEnable",&bValue);
    if(isError()){
        m_ParasInfo.PRNUCROIEnable = bValue;
    }
    retInfo(QString("PRNUCROIEnable %0 %1").arg(m_ParasInfo.PRNUCROIEnable).arg(getError()));

    // errRet = GetBoolValue("PRNUCUSEREnable",&bValue);
    // if(isError()){
    //     m_ParasInfo.PRNUCUSEREnable = bValue;
    // }
    // retInfo(QString("PRNUCUSEREnable %0 %1").arg(m_ParasInfo.PRNUCUSEREnable).arg(getError()));
}

//保存缺省参数
bool MVS::savePara(void){
    errRet = SetCommand("UserSetSave");
    retInfo(QString("savePara  UserSetSave %0").arg(getError()));
    return isError();
}

// 设置当前镜头
void MVS::setImage(void){
    // if(fsConf->imageConf==0){
    //     // 按厂家参数
    //     //        bool b = false;
    //     if(//(fsConf->curImage()->ExposureTime != m_ParasInfo.ExposureTime) ||
    //         (fsConf->curImage()->ExposureLines = m_ParasInfo.ExposureLines) ||
    //         //           (fsConf->curImage()->GainRed = m_ParasInfo.GainRed) ||
    //         //           (fsConf->curImage()->GainGreen = m_ParasInfo.GainGreen) ||
    //         //           (fsConf->curImage()->GainBlue = m_ParasInfo.GainBlue) ||
    //         (fsConf->curImage()->Contrast = m_ParasInfo.Contrast) ||
    //         (fsConf->curImage()->Light = m_ParasInfo.Brightness) ||
    //         (fsConf->curImage()->Saturation = m_ParasInfo.Saturation) ||
    //         (fsConf->curImage()->Gamma = m_ParasInfo.Gamma)){
    //         //                fsConf->curImage()->ExposureTime = m_ParasInfo.ExposureTime;
    //         fsConf->curImage()->ExposureLines = m_ParasInfo.ExposureLines;
    //         //                fsConf->curImage()->GainRed = m_ParasInfo.GainRed;
    //         //                fsConf->curImage()->GainGreen = m_ParasInfo.GainGreen;
    //         //                fsConf->curImage()->GainBlue = m_ParasInfo.GainBlue;
    //         fsConf->curImage()->Contrast = m_ParasInfo.Contrast;
    //         fsConf->curImage()->Light = m_ParasInfo.Brightness;
    //         fsConf->curImage()->Saturation = m_ParasInfo.Saturation;
    //         fsConf->curImage()->Gamma = m_ParasInfo.Gamma;
    //         fsConf->saveConfigImageSave();
    //     }
    // }
}

bool MVS::IsColor(MvGvspPixelType enType)
{
    switch(enType)
    {
    case PixelType_Gvsp_BGR8_Packed:
    case PixelType_Gvsp_YUV422_Packed:
    case PixelType_Gvsp_YUV422_YUYV_Packed:
    case PixelType_Gvsp_BayerGR8:
    case PixelType_Gvsp_BayerRG8:
    case PixelType_Gvsp_BayerGB8:
    case PixelType_Gvsp_BayerBG8:
    case PixelType_Gvsp_BayerGB10:
    case PixelType_Gvsp_BayerGB10_Packed:
    case PixelType_Gvsp_BayerBG10:
    case PixelType_Gvsp_BayerBG10_Packed:
    case PixelType_Gvsp_BayerRG10:
    case PixelType_Gvsp_BayerRG10_Packed:
    case PixelType_Gvsp_BayerGR10:
    case PixelType_Gvsp_BayerGR10_Packed:
    case PixelType_Gvsp_BayerGB12:
    case PixelType_Gvsp_BayerGB12_Packed:
    case PixelType_Gvsp_BayerBG12:
    case PixelType_Gvsp_BayerBG12_Packed:
    case PixelType_Gvsp_BayerRG12:
    case PixelType_Gvsp_BayerRG12_Packed:
    case PixelType_Gvsp_BayerGR12:
    case PixelType_Gvsp_BayerGR12_Packed:
        return true;
    default:
        return false;
    }
}

bool MVS::IsMono(MvGvspPixelType enType)
{
    switch(enType)
    {
    case PixelType_Gvsp_Mono10:
    case PixelType_Gvsp_Mono10_Packed:
    case PixelType_Gvsp_Mono12:
    case PixelType_Gvsp_Mono12_Packed:
        return true;
    default:
        return false;
    }
}


bool MVS::setImageFormat(int nValue){
    MvGvspPixelType nType;
    if(nValue == 1){
        nType = PixelType_Gvsp_RGB8_Packed;
    }else{
        nType = PixelType_Gvsp_Mono8;
    }
    errRet = SetEnumValue("PixelFormat",nType);
    retInfo(QString("setImageFormat %0 -> %1 ret %2").arg(nValue).arg(nType).arg(errRet));
    saveErrorMsg(QString("SetEnumValue(PixelFormat,%0,)").arg(nType));
    if(isError()){
        m_ParasInfo.ImageFormat = nValue;
    }
    return isError();
}

//bool MVS::setHorizontal(int nValue){

//}
//void MVS::getHorizontal(int &nValue){

//}

void MVS::saveErrorMsg(const QString msg){
    saveError(msg,errRet,0);
}

//枚举网络设备
int MVS::EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList){
    return MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, pstDevList);
}

bool MVS::IsDeviceAccessible(MV_CC_DEVICE_INFO* pstDevInfo, unsigned int nAccessMode){
    return MV_CC_IsDeviceAccessible(pstDevInfo, nAccessMode);
}

int MVS::openCamera(void){
    if(m_Device == MV_NULL){
        return MV_E_PARAMETER;
    }
    if(m_hDevHandle){
        return MV_E_CALLORDER;
    }
    //创建句柄
    errRet  = MV_CC_CreateHandle(&m_hDevHandle, m_Device);
    saveErrorMsg(QString("MV_CC_CreateHandle(,)"));
    if(errRet != MV_OK){
        return -2;
    }
    //打开设备
    errRet = MV_CC_OpenDevice(m_hDevHandle);
    if(errRet != MV_OK){
        closeCamera();
        return -3;
    }
    isOpenDevice = true;
    //获取所有参数
    getParms();
    return errRet;
}

//关闭相机
void MVS::closeCamera(void){
    if(isStartGrabbing)
    {
        stopGrabbing();
    }
    savePara();
    if (MV_NULL != m_hDevHandle)
    {
        MV_CC_CloseDevice(m_hDevHandle);
        MV_CC_DestroyHandle(m_hDevHandle);
    }
    m_hDevHandle = MV_NULL;
    isOpenDevice = false;
}

bool MVS::IsDeviceConnected(){
    return MV_CC_IsDeviceConnected(m_hDevHandle);
}

// void MVS::getFrameRate(float &rate){
//     rate = 0.0;
//     if(!isFrameCallback)return;
// }

// void MVS::setFrameTime(int64_t stamp){
//     if(!isFrameCallback)return;
// }

// ch:注册图像数据回调 | en:Register Image Data CallBack
bool MVS::RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser), void* pUser)
{
    if(pUser == nullptr || cbOutput == nullptr){
        if(!isFrameCallback)return MV_OK;
        isFrameCallback = false;
    }else{
        if(isFrameCallback)return MV_OK;
        isFrameCallback = true;
    }
    errRet = MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser);
    retInfo(QString("RegisterImageCallBack %0").arg(getError()));
    return isError();
}

bool MVS::AddEvent(void){
    errRet = MV_CC_SetEnumValueByString(m_hDevHandle,"EventSelector","ExposureEnd");
    retInfo(QString("AddEvent %0").arg(getError()));
    return isError();
}

// 注册事件回调
bool MVS::RegisterEventCallBack(void(__stdcall* cbOutput)(MV_EVENT_OUT_INFO* pEventInfo, void* pUser), void* pUser)
{
    if(pUser == nullptr || cbOutput == nullptr){
        if(!isEventCallback)return MV_OK;
        isEventCallback = false;
    }else{
        if(isEventCallback)return MV_OK;
        isEventCallback = true;
    }
    errRet = MV_CC_RegisterEventCallBackEx(m_hDevHandle, "ExposureEnd", cbOutput, pUser);
    retInfo(QString("RegisterEventCallBack %0").arg(getError()));
    return isError();
}

bool MVS::startGrabbing(void){
    errRet = MV_CC_StartGrabbing(m_hDevHandle);
    saveErrorMsg(QString("MV_CC_StartGrabbing(,) %0").arg(errRet));
    isStartGrabbing = isError();
    if(isStartGrabbing){
        curEncodeCounter = 0;
        curEncodeTimer = 0;
    }
    return isStartGrabbing;
}

void MVS::stopGrabbing(void){
    errRet = MV_CC_StopGrabbing(m_hDevHandle);
    saveErrorMsg(QString("MV_CC_StopGrabbing(,) %0").arg(errRet));
    isStartGrabbing = false;
}

//设置心跳时间
int MVS::setHeartBeatTime(unsigned int time){
    //心跳时间最小为500ms
    if(time<500)
        time=500;
    errRet = MV_CC_SetIntValue(m_hDevHandle, "GevHeartbeatTimeout", time);
    saveErrorMsg(QString("GevHeartbeatTimeout(%0,)").arg(time));
    return errRet;
}

bool MVS::getExposureTime(float &nValue,float &nMin,float &nMax){
    MVCC_FLOATVALUE stFloatValue = {0};
    errRet = GetFloatValue("ExposureTime", &stFloatValue);
    saveErrorMsg(QString("getExposureTime(,)"));
    if (isError())
    {
        nValue = stFloatValue.fCurValue;
        nMin = stFloatValue.fMin;
        nMax = stFloatValue.fMax;
    }
    return isError();
}

//设置曝光时间
bool MVS::setExposureTime(float ExposureTime){
    MVCC_FLOATVALUE stFloatValue = {0};
    SetEnumValue("ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF);
    stFloatValue.fCurValue = ExposureTime;
    errRet = MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime",stFloatValue.fCurValue);
    saveErrorMsg(QString("setExposureTime(%0,%1)").arg(getNumber(ExposureTime)).arg(isError()));
    if(isError()){
        m_ParasInfo.ExposureTime = ExposureTime;
    }
    return isError();
}

void MVS::getUptime(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    GetIntValue("DeviceUptime",&stIntValue);
    m_ParasInfo.DeviceUptime = stIntValue.nCurValue;
}

void MVS::getResulting(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    errRet = GetIntValue("ResultingLineRate",&stIntValue);
    if(isError()){
        m_ParasInfo.ResultingLineRate = stIntValue.nCurValue;
    }
    if(m_ParasInfo.AcquisitionMode){
        errRet = GetIntValue("AcquisitionBurstFrameCount",&stIntValue);
        if(isError()){
            m_ParasInfo.AcquisitionBurstFrameCount = stIntValue.nCurValue;
        }
    }
    MVCC_FLOATVALUE stFloatValue = {0};
    errRet = GetFloatValue("ResultingFrameRate",&stFloatValue);
    if(isError()){
        m_ParasInfo.ResultingFrameRate = stFloatValue.fCurValue;
    }
    // errRet = GetIntValue("GevLinkSpeed",&stIntValue);
    // if(isError()){
    //     m_ParasInfo.DeviceLinkSpeed = (float)stIntValue.nCurValue/1000.0;
    // }
    //计算带宽
    int bps = (8 + m_ParasInfo.ImageFormat*16)* m_ParasInfo.Width * m_ParasInfo.Height;
    m_ParasInfo.DeviceLinkSpeed = m_ParasInfo.ResultingFrameRate * (float)bps /1024.0/1024.0;
    errRet = GetIntValue("EncoderCounter",&stIntValue);
    if(isError()){
        m_ParasInfo.EncoderCounter = stIntValue.nCurValue;
    }
}

// 图像宽度/高度
bool MVS::getWidth(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    errRet = GetIntValue("Width",&stIntValue);
    if(isError()){
        m_ParasInfo.Width = stIntValue.nCurValue;
    }
    return isError();
}
bool MVS::setWidth(int width){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = width;
    errRet = SetIntValue("Width", stIntValue.nCurValue);
    saveErrorMsg(QString("setWidth(%0,%1)").arg(width).arg(isError()));
    if(isError()){
        m_ParasInfo.Height = stIntValue.nCurValue;
    }
    return isError();
}
bool MVS::getHeight(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    errRet = GetIntValue("Height",&stIntValue);
    if(isError()){
        m_ParasInfo.Height = stIntValue.nCurValue;
    }
    return isError();
}
bool MVS::setHeight(int height){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = height;
    errRet = SetIntValue("Height", stIntValue.nCurValue);
    saveErrorMsg(QString("setHeight(%0,%1)").arg(height).arg(isError()));
    if(isError()){
        m_ParasInfo.Height = stIntValue.nCurValue;
    }
    return isError();
}
//行频
bool MVS::getLineRate(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    errRet = GetIntValue("AcquisitionLineRate",&stIntValue);
    if(isError()){
        m_ParasInfo.AcquisitionLineRate = stIntValue.nCurValue;
    }
    return isError();
}
bool MVS::setLineRate(int rate){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = rate;
    errRet = SetIntValue("AcquisitionLineRate", stIntValue.nCurValue);
    saveErrorMsg(QString("setLineRate(%0,%1)").arg(rate).arg(isError()));
    if(isError()){
        m_ParasInfo.AcquisitionLineRate = stIntValue.nCurValue;
    }
    return isError();
}

bool MVS::getLineRateEnable(void){
    bool bValue;
    errRet = GetBoolValue("AcquisitionLineRateEnable",&bValue);
    if(isError()){
        m_ParasInfo.AcquisitionLineRateEnable = bValue;
    }
    return isError();
}

bool MVS::setLineRateEnable(bool enable){
    bool bValue = enable;
    errRet = SetBoolValue("AcquisitionLineRateEnable",bValue);
    if(isError()){
        m_ParasInfo.AcquisitionLineRateEnable = bValue;
    }
    return isError();
}

//设置关闭触发模式
bool MVS::setTriggerMode(bool enable){
    unsigned int value = MV_TRIGGER_MODE_OFF;
    if(enable){
        value = MV_TRIGGER_MODE_ON;
    }
    errRet = SetEnumValue("TriggerMode", value);
    saveErrorMsg(QString("SetEnumValue(TriggerMode,%0)").arg(enable));
    if(isError()){
        m_ParasInfo.TriggerMode = enable;
    }
    return isError();
}

//调节前置
bool MVS::setPreDivider(int value){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = value;
    errRet = SetIntValue("PreDivider", stIntValue.nCurValue);
    saveErrorMsg(QString("setPreDivider(%0,%1)").arg(value).arg(isError()));
    if(isError()){
        m_ParasInfo.PreDivider = stIntValue.nCurValue;
    }
    return isError();
}

//调节倍频
bool MVS::setMultiplier(int value){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = value;
    errRet = SetIntValue("Multiplier", stIntValue.nCurValue);
    saveErrorMsg(QString("setMultiplier(%0,%1)").arg(value).arg(isError()));
    if(isError()){
        m_ParasInfo.Multiplier = stIntValue.nCurValue;
    }
    return isError();
}

//调节后置
bool MVS::setPostDivider(int value){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    stIntValue.nCurValue = value;
    errRet = SetIntValue("PostDivider", stIntValue.nCurValue);
    saveErrorMsg(QString("setPostDivider(%0,%1)").arg(value).arg(isError()));
    if(isError()){
        m_ParasInfo.PostDivider = stIntValue.nCurValue;
    }
    return isError();
}

bool MVS::getEncode(void){
    MVCC_INTVALUE_EX stIntValue = { 0 };
    errRet = GetIntValue("EncoderCounter",&stIntValue);
    if(isError()){
        m_ParasInfo.EncoderCounter = stIntValue.nCurValue;
    }
    // retInfo(QString("EncoderCounter %0 %1").arg(m_ParasInfo.EncoderCounter).arg(getError()));
    if(curEncodeCounter==0 && curEncodeTimer == 0){
        curEncodeCounter = m_ParasInfo.EncoderCounter;
        curEncodeTimer = QDateTime::currentMSecsSinceEpoch();
        return false;
    }
    curFrameEncodeTimer = QDateTime::currentMSecsSinceEpoch() - curEncodeTimer;
    // retInfo(QString("getEncode %0 %1").arg(m_ParasInfo.EncoderCounter).arg(curEncodeCounter));
    if(m_ParasInfo.EncoderCounter>=curEncodeCounter){
        curFrameEncodeCounter = m_ParasInfo.EncoderCounter - curEncodeCounter;
    }else{
        curFrameEncodeCounter = m_ParasInfo.EncoderCounterMax + m_ParasInfo.EncoderCounter - curEncodeCounter;
    }
    curEncodeCounter = m_ParasInfo.EncoderCounter;
    curEncodeTimer = QDateTime::currentMSecsSinceEpoch();
    return true;
}

bool MVS::isEncodeOver(int timer){
    if(curEncodeCounter==0){
        getEncode();
    }
    return (QDateTime::currentMSecsSinceEpoch()-curEncodeTimer)>timer;
}

// 参数:获取/设置色度
// int MVS::getHue(int &nValue,int &nMin,int &nMax){
//     MVCC_INTVALUE_EX stIntValue = {0};
//     errRet = GetIntValue("Hue", &stIntValue);
//     saveErrorMsg(QString("getHue(,)"));
//     if (isError())
//     {
//         nValue = stIntValue.nCurValue;
//         nMin = stIntValue.nMin;
//         nMax = stIntValue.nMax;
//     }
//     return errRet;
// }
// bool MVS::setHue(int hue){
//     if(m_ParasInfo.Contrast == hue)return false;
//     SetBoolValue("HueEnable", true);
//     errRet = MV_CC_SetIntValue(m_hDevHandle, "Hue",hue);
//     saveErrorMsg(QString("setHue(%0,)").arg(hue));
//     return errRet;
//     if(isError()){
//         m_ParasInfo.Contrast = hue;
//     }
//     return isError();
// }
// 参数:获取/设置亮度
// int MVS::getBrightness(int &nValue,int &nMin,int &nMax){
//     MVCC_INTVALUE_EX stIntValue = {0};
//     errRet = GetIntValue("Brightness", &stIntValue);
//     saveErrorMsg(QString("getBrightness(,)"));
//     if (isError())
//     {
//         nValue = stIntValue.nCurValue;
//         nMin = stIntValue.nMin;
//         nMax = stIntValue.nMax;
//     }
//     return errRet;
// }
// bool MVS::setBrightness(int brightness){
//     if(m_ParasInfo.Brightness == brightness)return false;
//     errRet = MV_CC_SetIntValue(m_hDevHandle, "Brightness",brightness);
//     saveErrorMsg(QString("setBrightness(%0,)").arg(brightness));
//     if(isError()){
//         m_ParasInfo.Brightness = brightness;
//     }
//     return isError();
// }
// 参数:获取/设置饱和度
// int MVS::getSaturation(int &nValue,int &nMin,int &nMax){
//     MVCC_INTVALUE_EX stIntValue = {0};
//     errRet = GetIntValue("Saturation", &stIntValue);
//     saveErrorMsg(QString("getSaturation(,)"));
//     if (isError())
//     {
//         nValue = stIntValue.nCurValue;
//         nMin = stIntValue.nMin;
//         nMax = stIntValue.nMax;
//     }
//     return errRet;
// }
// bool MVS::setSaturation(int saturation){
//     if(m_ParasInfo.Saturation == saturation)return false;
//     SetBoolValue("SaturationEnable", true);
//     errRet = MV_CC_SetIntValue(m_hDevHandle, "Saturation",saturation);
//     saveErrorMsg(QString("setSaturation(%0,)").arg(saturation));
//     if(isError()){
//         m_ParasInfo.Saturation = saturation;
//     }
//     return isError();
// }
// 参数:获取/设置伽马
// int MVS::getGamma(int &nValue,int &nMin,int &nMax){
//     MVCC_INTVALUE_EX stIntValue = {0};
//     errRet = GetIntValue("Gamma", &stIntValue);
//     saveErrorMsg(QString("getGamma(,)"));
//     if (isError())
//     {
//         nValue = stIntValue.nCurValue;
//         nMin = stIntValue.nMin;
//         nMax = stIntValue.nMax;
//     }
//     return errRet;
// }
// bool MVS::setGamma(int gamma){
//     if(m_ParasInfo.Gamma == gamma)return false;
//     SetBoolValue("GammaEnable", true);
//     errRet = MV_CC_SetIntValue(m_hDevHandle, "Gamma",gamma);
//     saveErrorMsg(QString("setGamma(%0,)").arg(gamma));
//     if(isError()){
//         m_ParasInfo.Gamma = gamma;
//     }
//     return isError();
// }

//显示窗口
// int MVS::DisplayOneFrame(MV_DISPLAY_FRAME_INFO* pDisplayInfo){
//     errRet = MV_CC_DisplayOneFrame(m_hDevHandle, pDisplayInfo);
//     saveErrorMsg(QString("MV_CC_DisplayOneFrame(,)"));
//     return errRet;
// }

//转换图像
// int MVS::convertPixelType(MV_CC_PIXEL_CONVERT_PARAM *param){
//     errRet = MV_CC_ConvertPixelType(m_hDevHandle, param);
//     saveErrorMsg(QString("MV_CC_ConvertPixelType(,)"));
//     return errRet;
// }

int MVS::GetIntValue(IN const char* strKey, OUT MVCC_INTVALUE_EX *pIntValue){
    return MV_CC_GetIntValueEx(m_hDevHandle, strKey, pIntValue);
}

int MVS::SetIntValue(IN const char* strKey, IN int64_t nValue){
    return MV_CC_SetIntValueEx(m_hDevHandle, strKey, nValue);
}

int MVS::GetEnumValue(IN const char* strKey, OUT MVCC_ENUMVALUE *pEnumValue){
    return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue);
}

int MVS::SetEnumValue(IN const char* strKey, IN unsigned int nValue){
    return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
}

int MVS::SetEnumValueByString(IN const char* strKey, IN const char* sValue){
    return MV_CC_SetEnumValueByString(m_hDevHandle, strKey, sValue);
}

int MVS::GetEnumEntrySymbolic(IN const char* strKey, IN MVCC_ENUMENTRY* pstEnumEntry){
    return MV_CC_GetEnumEntrySymbolic(m_hDevHandle, strKey, pstEnumEntry);
}

int MVS::GetFloatValue(IN const char* strKey, OUT MVCC_FLOATVALUE *pFloatValue){
    return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue);
}

int MVS::SetFloatValue(IN const char* strKey, IN float fValue){
    return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
}

int MVS::GetBoolValue(IN const char* strKey, OUT bool *pbValue){
    return MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue);
}

int MVS::SetBoolValue(IN const char* strKey, IN bool bValue){
    return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
}

int MVS::GetStringValue(IN const char* strKey, MVCC_STRINGVALUE *pStringValue){
    return MV_CC_GetStringValue(m_hDevHandle, strKey, pStringValue);
}

int MVS::SetStringValue(IN const char* strKey, IN const char * strValue){
    return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue);
}

int MVS::SetCommand(IN const char* strKey){
    return MV_CC_SetCommandValue(m_hDevHandle, strKey);
}
